#include <exception>
#include "fun.h"
#include "logger.h"

using namespace std;
using namespace cv;

std::vector<std::string> readFile(std::string videoPath) {
    std::vector<std::string> vfile;
    std::fstream file_in(videoPath, std::ios::in);
    std::string temp_line;
    while (std::getline(file_in, temp_line)) {
        if (temp_line != "")
            vfile.push_back(temp_line);
    }
    file_in.close();
    return vfile;
}



int primaryFilter(std::string videoPath, VideoCapture cap, PresetPara pPara){
   if( !cap.isOpened()){
        logger::record() << videoPath << "  video can not be opened!";
        return -1;
    }

    if(pPara.fps){
        double fps = cap.get(cv::CAP_PROP_FPS);
        if(abs(fps - pPara.fps) > 1){
            logger::record() << videoPath << "  video's fps: "<< fps << " != "<< pPara.fps;
            return -1;
        }
    }
    if(pPara.duration){
        double fps = cap.get(cv::CAP_PROP_FPS);
        int frame_cn = cap.get(CAP_PROP_FRAME_COUNT);
        if(0 == frame_cn){
            logger::record()<< videoPath << " video total frames is 0!";
            return -1;
        }
        if (abs(frame_cn / fps) - pPara.duration > 1){
            logger::record() << videoPath << "  video duration: "<< frame_cn / fps << " != " <<pPara.duration;
            return -1;
        }
    }
    if(0 != pPara.frame_h && 0 != pPara.frame_w){
        double h = cap.get(CAP_PROP_FRAME_HEIGHT);
        double w = cap.get(CAP_PROP_FRAME_WIDTH);
        if(h != pPara.frame_h || w != pPara.frame_w){
            logger::record() << videoPath << "video reslution: ("<< h<<", "<<w<<") != ("<< pPara.frame_h<<", "<<pPara.frame_w<<")";
            return -1;
        }
    }
    return 0;
}


#define BUFFER_SIZE 64
double getDuration(std::string videoPath){
    std::string cmd = "ffprobe -select_streams v -show_entries format=duration,size,bit_rate -v quiet -i " + videoPath + " |grep duration |awk  -F '=' '{print $2}'";
    FILE *read_fp = NULL;
    char buffer[BUFFER_SIZE + 1];
    char *pBuffer;
    memset(buffer, 0, sizeof(buffer));
    read_fp = popen(cmd.c_str(), "r");
    if(read_fp == NULL){
        return 0;
    }else{
        fgets(buffer, BUFFER_SIZE, read_fp);
        pBuffer = buffer;
        return atof(pBuffer);
    }
}

#define _MAXMISSINGFRAMENUM_ 60
int frameAnalysis(std::string videoPath, VideoCapture cap){
    Mat frame;
    int frame_cn = cap.get(CAP_PROP_FRAME_COUNT);
    int missingFrameNum = 0;
    double POS_MSEC = 0;
    while (missingFrameNum < _MAXMISSINGFRAMENUM_) {
        if(frame_cn < missingFrameNum + 1){
            logger::record()<< videoPath << " video total frames less than "<< missingFrameNum + 1 ;
            return -1;
        }
        cap.set(CAP_PROP_POS_FRAMES, frame_cn - missingFrameNum - 1);
        cap >> frame;
        POS_MSEC = cap.get(CAP_PROP_POS_MSEC);
        if(POS_MSEC > 10){ break;}
        missingFrameNum++;
    }


    if(0 == missingFrameNum){
        double duration = getDuration(videoPath);
        if(duration < 0.001){
            //cout << videoPath<<" get video duration error!"<<endl;
            logger::record()<< videoPath << " video duration error!";
            return -1;
        }
        if(abs(POS_MSEC/1000. - duration) > 1){
            //cout << videoPath<<" video actual time  "<< POS_MSEC/1000.  <<"s != "<< duration <<"s (video duration)"<<endl;
            logger::record()<< videoPath << "  video time "<< POS_MSEC/1000.  <<"s (actual) != "<< duration<<"s (duration)";
            return -1;
        }else {
            // video is normal
            return 0;
        }

    }else if (missingFrameNum < _MAXMISSINGFRAMENUM_){
        //cout <<"video missing "<< missingFrameNum <<" frames!" << endl;
        logger::record()<< videoPath << "  video loss "<< missingFrameNum << " frames!";
        return -1;
    }else{
        //cout << videoPath << "video missing more than "<< missingFrameNum <<" frames!" <<endl;
        logger::record()<< videoPath << "  video loss more than "<< missingFrameNum << " frames!";
        return -1;
    }
    return 0;
}
